<?php

namespace app\common\service;

class TokenService
{
    /**
     * 生成token
     *
     * @param array $data 用户数据
     * @param int $expire 过期时间（秒）
     * @return string
     */
    public static function generateToken(array $data, int $expire = 7200): string
    {
        $payload = [
            'data' => $data,
            'exp' => time() + $expire,
            'iat' => time()
        ];

        return self::encode($payload);
    }

    /**
     * 验证token
     *
     * @param string $token
     * @return array|null
     */
    public static function verifyToken(string $token): ?array
    {
        try {
            $payload = self::decode($token);

            // 检查token是否过期
            if (isset($payload['exp']) && $payload['exp'] < time()) {
                return null; // token已过期
            }

            return $payload;
        } catch (\Exception $e) {
            return null; // token无效
        }
    }

    /**
     * 从请求头获取token
     *
     * @param \think\Request $request
     * @return string|null
     */
    public static function getTokenFromRequest(\think\Request $request): ?string
    {
        // 从Header中获取token
        $token = $request->header('Authorization');

        if ($token && strpos($token, 'Bearer ') === 0) {
            return substr($token, 7);
        }

        // 从GET/POST参数中获取token
        return $request->param('token');
    }

    /**
     * 编码payload为token
     *
     * @param array $payload
     * @return string
     */
    private static function encode(array $payload): string
    {
        $header = [
            'typ' => 'JWT',
            'alg' => 'HS256'
        ];

        $headerEncoded = self::base64UrlEncode(json_encode($header));
        $payloadEncoded = self::base64UrlEncode(json_encode($payload));
        $signature = self::generateSignature($headerEncoded, $payloadEncoded);

        return $headerEncoded . '.' . $payloadEncoded . '.' . $signature;
    }

    /**
     * 解码token
     *
     * @param string $token
     * @return array
     * @throws \Exception
     */
    private static function decode(string $token): array
    {
        $parts = explode('.', $token);

        if (count($parts) !== 3) {
            throw new \Exception('Invalid token format');
        }

        [$headerEncoded, $payloadEncoded, $signature] = $parts;

        // 验证签名
        $expectedSignature = self::generateSignature($headerEncoded, $payloadEncoded);
        if ($signature !== $expectedSignature) {
            throw new \Exception('Invalid token signature');
        }

        $payload = json_decode(self::base64UrlDecode($payloadEncoded), true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new \Exception('Invalid payload JSON');
        }

        return $payload;
    }

    /**
     * 生成签名
     *
     * @param string $header
     * @param string $payload
     * @return string
     */
    private static function generateSignature(string $header, string $payload): string
    {
        $key = config('app.token_secret', 'default_secret_key');
        $data = $header . '.' . $payload;
        return self::base64UrlEncode(hash_hmac('sha256', $data, $key, true));
    }

    /**
     * Base64 URL编码
     *
     * @param string $data
     * @return string
     */
    private static function base64UrlEncode(string $data): string
    {
        return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
    }

    /**
     * Base64 URL解码
     *
     * @param string $data
     * @return string
     */
    private static function base64UrlDecode(string $data): string
    {
        return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
    }
}
